package cn.bluethink.eguan.okrtask.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;

import cn.bluethink.eguan.core.service.AEgPosObjectService;
import cn.bluethink.eguan.core.service.EgActionService;
import cn.bluethink.eguan.core.service.EgCommentService;
import cn.bluethink.eguan.core.service.EgFileService;
import cn.bluethink.eguan.core.service.EgPosObjectService;
import cn.bluethink.eguan.core.service.EgResultService;
import cn.bluethink.eguan.core.service.EgTaskService;
import cn.bluethink.eguan.core.service.EgTavernService;
import cn.bluethink.eguan.core.service.EgUserPurviewService;
import cn.bluethink.eguan.core.service.EgUserService;
import cn.bluethink.eguan.model.core.EgActionType;
import cn.bluethink.eguan.model.core.EgConfigInfo;
import cn.bluethink.eguan.model.core.EgFile;
import cn.bluethink.eguan.model.core.EgOType;
import cn.bluethink.eguan.model.core.EgObject;
import cn.bluethink.eguan.model.core.EgOtAction;
import cn.bluethink.eguan.model.core.EgProirity;
import cn.bluethink.eguan.model.core.EgResult;
import cn.bluethink.eguan.model.core.EgRole;
import cn.bluethink.eguan.model.core.EgTask;
import cn.bluethink.eguan.model.core.EgTaskStatus;
import cn.bluethink.eguan.model.core.EgTavern;
import cn.bluethink.eguan.model.core.EgUser;
import cn.bluethink.eguan.model.okrtask.EgOkrTask;
import cn.bluethink.eguan.model.okrtask.EgTimingType;
import cn.bluethink.eguan.okrtask.entity.EgOKRTaskEntity;
import cn.bluethink.eguan.okrtask.entity.OKRTaskEntity;
import cn.bluethink.eguan.okrtask.filter.OkrTaskFilter;
import cn.bluethink.eguan.okrtask.mapper.EgOKRTaskMapper;
import cn.bluethink.eguan.result.PageInfo;
import cn.bluethink.eguan.utils.DateUtil;
import cn.bluethink.eguan.utils.OkrTaskUtil;
import tk.mybatis.mapper.entity.Example;

@Service
public class EgOKRTaskService extends AEgPosObjectService {

    @Autowired
    private EgConfigInfo configInfo;

    @Autowired
    private EgOKRTaskMapper okrTaskMapper;

    @Autowired
    private EgTaskService taskService;

    @Autowired
    private EgTaskKRService krService;

    @Autowired
    private EgCommentService commentService;

    @Autowired
    private EgUserService userService;

    @Autowired
    private EgPosObjectService posObjectService;

    @Autowired
    private EgUserPurviewService purviewService;

    @Autowired
    private EgActionService actionService;

    @Autowired
    private EgTavernService tavernService;

    @Autowired
    private EgFileService fileService;

    @Autowired
    private EgResultService resultService;

    private OkrTaskUtil okrTaskUtil = new OkrTaskUtil();

    @Override
    public Integer posOtype() {
        return EgOType.OKR_TASK;
    }

    @Override
    public EgObject pos(Long posid) throws Exception {
        return taskService.detail(posid, this.posOtype());
    }

    /**
     * 发布工作任务
     * 
     * @param okrTask
     * @return
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    public EgOkrTask create(EgOkrTask okrTask, Long uid) throws Exception {
        // 1、设置任务类型为工作任务,设置所在位置类型为驿馆
        EgOType type = configInfo.otypes().get(EgOType.OKR_TASK);
        okrTask.setType(type);
        EgOType postype = configInfo.otypes().get(EgOType.TAVERN);
        okrTask.getPos().setType(postype);
        // 2、如果有截止日期，实际截止时间为当前日期下午6点
        if (okrTask.getEtime() != null) {
            okrTask.setEtime(DateUtil.dateTime(okrTask.getEtime(), 18, 0, 0));
            if (DateUtil.dateCompare(new Date(), okrTask.getEtime()) > 0)
                okrTask.setStatus(EgTaskStatus.STATUS_DELAY);
        }
        // 3、设置任务发布者信息
        EgUser user = new EgUser(uid, null, null);
        okrTask.setCuser(user);
        // 4、将工作任务模型转换为工作任务实体
        EgOKRTaskEntity entity = new EgOKRTaskEntity(okrTask, true);
        // 获取计划中工作任务总个数，并设置默认顺序
        int sort = countByStatus(okrTask.getPos(), EgTaskStatus.STATUS_NEW);
        entity.setSort(sort + 1);
        // 5、创建通用任务
        EgTask task = taskService.create(okrTask);
        if (task == null)
            return null;
        // 6、通用任务创建成功，设置工作任务ID
        entity.setTid(task.getId());
        // 7、创建工作任务
        int count = okrTaskMapper.insert(entity);
        if (count == 0)
            return null;
        okrTask = entity.createOkr(task);
        // 8.创建动作
        int atid = EgActionType.CREATE;
        if (!saveAction(okrTask, atid, uid, null)) {
            throw new RuntimeException("新增动作失败！");
        }
        return okrTask;
    }

    /**
     * 更新工作任务
     * 
     * @param okrtask
     * @param updateokr
     * @param uid
     * @return
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    public EgOkrTask update(EgOkrTask okrtask, EgOkrTask updateokr, Long uid) throws Exception {
        // 1、设置任务类型为工作任务
        EgOType type = configInfo.otypes().get(EgOType.OKR_TASK);
        updateokr.setType(type);
        // 2、更新截止时间
        if (okrtask != null) {
            updateokr = updateStatusByEtime(okrtask, updateokr);
            // 更新目标的标识和截止时间
            updateokr = updateTimingAndEtime(okrtask, updateokr);
        }
        // 3、将工作任务模型转换为工作任务实体
        EgOKRTaskEntity entity = new EgOKRTaskEntity(updateokr, false);
        // 4、更新通用任务
        EgTask task = taskService.update(updateokr);
        if (task == null)
            return null;
        // 5、通用任务更新成功，更新工作任务
        int count = okrTaskMapper.updateOKRTask(entity);
        if (count == 0)
            return null;
        updateokr = entity.createOkr(task);
        // 计算label，返回标签
        if (okrtask != null) {
            updateokr.calculateLabel(tavernService.getBmonthByFid(okrtask.getPos().getId()));
        }
        // 只更新updateokr，计算标签
        if (okrtask == null) {
            updateokr.calculateLabel(tavernService.getBmonthByFid(updateokr.getPos().getId()));
        }
        // 6.更新动作
        if (okrtask != null && uid != null) {
            if (!updateAction(okrtask, updateokr, uid)) {
                throw new RuntimeException("新增动作失败！");
            }
        }
        return updateokr;
    }

    /**
     * 更新工作任务状态
     * 
     * @param okrTask
     * @param updateokr
     * @param uid
     * @return
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    public EgOkrTask updateStatus(EgOkrTask okrTask, EgOkrTask updateokr, Long uid) throws Exception {
        // 1、原工作任务状态
        int okrstatus = okrTask.getStatus();
        // 2、现更新的工作任务状态
        int updatestatus = updateokr.getStatus();
        // 3、获取更新的工作任务状态
        Integer status = getStatus(okrstatus, updatestatus);
        // 4、设置任务类型为工作任务
        EgOType type = configInfo.otypes().get(EgOType.OKR_TASK);
        updateokr.setType(type);
        if (status == null)
            return null;
        updateokr.setStatus(status);
        // 5、设置任务完成时间
        if ((status & EgTaskStatus.STATUS_FINISH) == EgTaskStatus.STATUS_FINISH) {
            updateokr.setFtime(new Date());
        }
        // 如果状态为进行中，并且原任务状态为已暂停，更新任务截止时间为null
        if ((status & EgTaskStatus.STATUS_HANDLE) == EgTaskStatus.STATUS_HANDLE
                && (okrstatus & EgTaskStatus.STATUS_PAUSE) == EgTaskStatus.STATUS_PAUSE) {
            updateokr.setEtime(null);
        } else {
            updateokr.setEtime(okrTask.getEtime());
        }
        // 状态更新时，更新任务排序
        if (updateSortByStatus(okrTask, updateokr) == null) {
            throw new Exception("任务更新失败！");
        }
        EgTask task = taskService.update(updateokr);
        if (task == null)
            return null;
        // 7.更新状态动作：开始/完成/重做
        int atid = 0;
        // 待更新的状态为进行中或者延误处理
        if ((status & EgTaskStatus.STATUS_HANDLE) == EgTaskStatus.STATUS_HANDLE) {
            atid = EgActionType.START;
            // 如果原状态不是未开始，则该动作为重做
            if (okrstatus != EgTaskStatus.STATUS_NEW) {
                atid = EgActionType.REDO;
            }
        }
        // 待更新的状态为完成或者延误完成
        else if ((status & EgTaskStatus.STATUS_FINISH) == EgTaskStatus.STATUS_FINISH) {
            atid = EgActionType.FINISH;
        } else if ((status & EgTaskStatus.STATUS_PAUSE) == EgTaskStatus.STATUS_PAUSE) {
            atid = EgActionType.PAUSE;
        }
        //
        if (atid > 0 && !saveAction(okrTask, atid, uid, null)) {
            throw new RuntimeException("新增动作失败！");
        }
        return updateokr;
    }

    /**
     * 根据主键Id删除工作任务（修改为逻辑删除）
     * 
     * @param uid
     * @param okrtask
     * @return
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    public Long del(Long uid, EgOkrTask okrtask) throws Exception {
        Long tid = okrtask.getId();
        // 获取将被删除的任务信息
        EgOkrTask oldtask = getById(tid);
        // 1、删除任务中的关键项
        if (krService.deleteByTid(tid) == null)
            return null;
        // 2、删除任务中的评论
        EgObject obj = new EgObject(tid, null, configInfo.otypes().get(EgOType.TAVERN));
        if (commentService.deleteByObj(obj) == null)
            return null;
        // 获取删除任务前，该任务所在列表中的任务总个数和当前任务的顺序
        EgOKRTaskEntity entity = okrTaskMapper.selectByPrimaryKey(oldtask.getId());
        int originalCount = countByStatus(oldtask.getPos(), oldtask.getStatus());

        // 删除工作任务前，取消与其相关的关联目标
        if (!removeTargets(tid)) {
            throw new RuntimeException("删除失败！");
        }
        int tasksort = entity.getSort();
        // 3、根据主键Id删除工作任务
        if (okrTaskMapper.deleteByPrimaryKey(tid) > 0) {
            // 4、根据主键ID和工作任务类型删除通用任务
            if (taskService.remove(tid, EgOType.OKR_TASK) == 0) {
                return null;
            }
        }

        // 5.删除动作
        int atid = EgActionType.DELETE;
        if (!saveAction(oldtask, atid, uid, null)) {
            throw new RuntimeException("新增动作失败！");
        }
        // 6、更新排序
        String sortSql = buildSortSql(tasksort, originalCount, oldtask.getStatus(), oldtask.getPos().getId(),
                oldtask.getPos().getType().getOtid(), false);
        okrTaskMapper.updateSort(sortSql, false);
        return tid;
    }

    /**
     * 根据主键Id获取工作任务详情
     * 
     * @param tid
     * @return 返回工作任务详情（包括任务发布人、指派人、任务结果、任务所在位置）
     * @throws Exception
     */
    public EgOkrTask detail(Long tid) throws Exception {
        // 1、查询通用任务
        EgTask task = taskService.detail(tid, EgOType.OKR_TASK);
        if (task == null)
            return null;
        // 2、存在通用任务，查询工作任务
        EgOKRTaskEntity entity = okrTaskMapper.selectByPrimaryKey(tid);
        if (entity == null)
            return null;
        // 3、将工作任务实体转换为工作任务模型
        EgOkrTask okrTask = entity.createOkr(task);
        // 4、设置指派人信息
        EgUser douser = new EgUser();
        if (entity.getDouid() != null) {
            douser = userService.getUserBasic(entity.getDouid());
        }
        okrTask.setDouser(douser);
        // 5、设置任务所在位置
        EgObject pos = posObjectService.pos(okrTask.getPos().getType().getOtid(), okrTask.getPos().getId());
        if (pos != null) {
            okrTask.setPos(pos);
            // 返回标签
            okrTask.calculateLabel(tavernService.getBmonthByFid(pos.getId()));
        }
        // 6、设置任务的提交结果列表
        Long rOid = entity.getResultOid();
        EgResult result = new EgResult(0L, null, new EgOType(EgOType.FILE_LIST, null));
        result.setFileList(new ArrayList<>());
        if (rOid != null && rOid > 0) {
            // 获取提交的结果信息(只返回提交的文件列表)
            EgResult rObj = resultService.detail(rOid);
            if (rObj != null) {
                result.setId(rOid);
                result.setFileList(rObj.getFileList());
            }
        }
        okrTask.setResult(result);
        // 设置关联的目标
        if (entity.getParent() != null && entity.getParent() > 0) {
            // 获取目标任务的基本信息
            EgTask targetTask = taskService.detail(entity.getParent(), EgOType.OKR_TASK);
            if (targetTask == null) return null;
        	EgOKRTaskEntity targetEntity = okrTaskMapper.selectByPrimaryKey(entity.getParent());;
            EgOkrTask target = new EgOkrTask(targetEntity.getTid(), targetTask.getName(), null);
            target.setTiming(targetEntity.getTiming());
            okrTask.setParent(target);
        }
        // 8、返回任务结果
        return okrTask;
    }

    /**
     * 根据过滤条件查询工作任务列表
     * 
     * @param filter
     * @return
     * @throws Exception
     */
    public PageInfo<EgOkrTask> query(OkrTaskFilter filter) throws Exception {
        Integer pageNum = filter.getPageNum() == null ? 1 : filter.getPageNum();
        Integer pageSize = filter.getPageSize() == null ? 20 : filter.getPageSize();
        // 1、构造查询条件
        String whereSql = buildQuerySQL(filter);
        String orderSql = buildOrderSql(filter, false);

        List<EgOkrTask> result = new ArrayList<>();
        Page<OKRTaskEntity> entities = PageHelper.startPage(pageNum, pageSize);
        // 判断whereSql不为空，根据条件查询工作任务列表
        if (whereSql != null && !whereSql.equals("")) {
            entities = okrTaskMapper.selectTasksByCondition(whereSql, orderSql);
        }
        if (entities == null || entities.size() == 0)
            return new PageInfo<>(result, entities);
        result = entities.stream().map(e -> e.createOKRTask()).collect(Collectors.toList());
        return new PageInfo<>(result, entities);
    }

    /**
     * 查询工作台 - 工作任务
     * 
     * @param filter
     * @param cuid
     * @return
     * @throws Exception
     */
    public PageInfo<EgOkrTask> myworkbench(OkrTaskFilter filter, Long cuid) throws Exception {
        Integer pageNum = filter.getPageNum() == null ? 1 : filter.getPageNum();
        Integer pageSize = filter.getPageSize() == null ? 20 : filter.getPageSize();
        // 1、构造查询条件
        String whereSql = buildMyworkbenchSQL(filter, cuid);
        String orderSql = buildOrderSql(filter, true);

        if (whereSql == null)
            return new PageInfo<>(new ArrayList<>());

        List<EgOkrTask> result = new ArrayList<>();
        List<OKRTaskEntity> resultentities = new ArrayList<>();
        Page<OKRTaskEntity> entities = PageHelper.startPage(pageNum, pageSize);
        // 判断whereSql不为空，根据条件查询工作任务列表
        if (whereSql != null && !whereSql.equals("")) {
            entities = okrTaskMapper.selectTasksByCondition(whereSql, orderSql);
        }
        if (entities == null || entities.size() == 0)
            return new PageInfo<>(result);
        Long fid = filter.getFid();
        if (fid == null || fid == 0) {
            // 根据驿馆进行分组
            LinkedHashMap<Long, List<OKRTaskEntity>> groupBy = entities.stream()
                    .collect(Collectors.groupingBy(OKRTaskEntity::getEgid, LinkedHashMap::new, Collectors.toList()));
            for (Entry<Long, List<OKRTaskEntity>> entry : groupBy.entrySet()) {
                List<OKRTaskEntity> list = entry.getValue();
                resultentities.addAll(list);
            }
            result = resultentities.stream().map(r -> r.createOKRTask()).collect(Collectors.toList());
        } else {
            result = entities.stream().map(e -> e.createOKRTask()).collect(Collectors.toList());
        }
        return new PageInfo<>(result, entities);
    }

    /**
     * 根据主键Id获取工作任务基本信息
     * 
     * @param tid
     * @return 返回工作任务信息
     * @throws Exception
     */
    public EgOkrTask getById(Long tid) throws Exception {
        // 查询任务
        EgTask task = taskService.detail(tid, EgOType.OKR_TASK);
        if (task == null)
            return null;
        // 查询工作任务
        EgOKRTaskEntity entity = okrTaskMapper.selectByPrimaryKey(tid);
        if (entity == null)
            return null;
        // 转换为工作模型
        EgOkrTask okrTask = entity.createOkr(task);
        okrTask.calculateLabel(tavernService.getBmonthByFid(okrTask.getPos().getId()));
        // 设置任务结果
        return okrTask;
    }

    /**
     * 获取用户在当前任务中的权限
     * 
     * @param okrTask
     * @param user
     * @return
     * @throws Exception
     */
    public EgRole roleintask(EgOkrTask okrTask, EgUser user) throws Exception {
        EgObject pos = okrTask.getPos();
        if (pos != null)
            pos = posObjectService.pos(pos.getType().getOtid(), pos.getId());
        EgRole role = purviewService.role(pos, user.getId(), user.getRole());
        return role;
    }

    /**
     * 批量上传文件（可重复上传，不覆盖）
     * 
     * @param okrTask
     * @param result
     * @param uid
     * @return
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    public List<EgFile> submit(EgOkrTask okrTask, EgResult result, Long uid) throws Exception {
        // 定义最终的所有提交文件
        List<EgFile> allFiles = new ArrayList<>();
        // 查询之前提交的文件
        List<Long> uids = Arrays.asList(new Long[] { uid });
        List<EgFile> oldFiles = fileService.queryByUploaders(okrTask.getId(), EgOType.OKR_TASK, uids);
        // 批量提交文件
        List<EgFile> subFiles = fileService.createList(result.getFileList());
        if (subFiles == null) {
            throw new RuntimeException("上传文件失败，请重试！");
        }
        allFiles.addAll(subFiles);
        if (oldFiles == null || oldFiles.size() == 0) {
            // 创建新的结果
            result.setFileList(subFiles);
            result = resultService.create(result);
        } else {
            // 更新新的提交结果，获取原来的结果对象ID
            allFiles.addAll(oldFiles);
            result.setId(okrTask.getResult().getId());
            result.setFileList(allFiles);
            result = resultService.update(result, true);
        }
        if (result == null) {
            throw new RuntimeException("提交结果失败，请重试！");
        }
        result.setFileList(allFiles);
        // 提交成果，获取新的结果对象ID以及提交时间
        EgResult newResult = new EgResult();
        newResult.setId(result.getId());
        okrTask.setResult(newResult);
        if (okrTaskMapper.updateOKRTask(new EgOKRTaskEntity(okrTask, false)) == 0) {
            throw new RuntimeException("提交结果失败，请重试！");
        }
        // 创建上传文件动作
        int atid = EgActionType.UPLOAD;
        if (!saveAction(okrTask, atid, uid, subFiles)) {
            throw new RuntimeException("新增文件上传动作失败！");
        }
        return allFiles;
    }

    /**
     * 删除指定的文件
     * 
     * @param file
     * @param okrtask
     * @param subResult
     * @param uid
     * @return
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    public Boolean delFile(EgFile file, EgOkrTask okrtask, EgResult subResult, Long uid) throws Exception {
        // 删除指定的文件
        if (!fileService.del(file.getId())) {
            throw new RuntimeException("删除文件失败，请重试！");
        }
        // 删除之后，获取剩余的文件列表
        List<Long> uids = Arrays.asList(new Long[] { uid });
        List<EgFile> remainFiles = fileService.queryByUploaders(okrtask.getId(), EgOType.OKR_TASK, uids);
        if (remainFiles != null && remainFiles.size() > 0) {
            // 只更新结果对象表，文件字符串的数目
            subResult.setFileList(remainFiles);
            if (resultService.update(subResult, true) == null) {
                throw new RuntimeException("删除文件失败，请重试！");
            }
        } else {
            // 更新工作任务的结果对象为null
            okrtask.setResult(null);
            if (okrTaskMapper.updateOKRTask(new EgOKRTaskEntity(okrtask, false)) == 0) {
                throw new RuntimeException("删除文件失败，请重试！");
            }
            // 删除结果表(此时文件已经删除了，无需删除了)
            if (!resultService.delete(subResult.getId(), false)) {
                throw new RuntimeException("删除文件失败，请重试！");
            }
        }
        // 创建删除文件动作
        int atid = EgActionType.DELETE;
        List<EgFile> files = Arrays.asList(new EgFile[] { file });
        if (!saveAction(okrtask, atid, uid, files)) {
            throw new RuntimeException("新增文件上传动作失败！");
        }
        return true;
    }

    /**
     * 前端拖拽排序
     * 
     * @param task
     * @param sort
     * @return
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    public Long sort(EgOkrTask task, Integer sort) throws Exception {
        EgOKRTaskEntity entity = okrTaskMapper.selectByPrimaryKey(task.getId());
        int status = task.getStatus();
        int tasksort = entity.getSort();
        // 如果顺序没有改变，不做任何调整
        if (sort == tasksort)
            return task.getId();
        int result = 0;
        String sortSql = "";
        // 1、如果向下拖拽，更新原来位置和拖拽位置之间的所有任务顺序
        if (sort > tasksort) {
            sortSql = buildSortSql(tasksort, sort, status, task.getPos().getId(), task.getPos().getType().getOtid(),
                    false);
            result = okrTaskMapper.updateSort(sortSql, false);
        }
        // 2、如果向上拖拽，更新原来位置和拖拽位置之间的所有任务顺序
        else {
            sortSql = buildSortSql(sort, tasksort, status, task.getPos().getId(), task.getPos().getType().getOtid(),
                    true);
            result = okrTaskMapper.updateSort(sortSql, true);
        }

        if (result > 0) {
            // 3、更新成功后，更新当前任务的顺序
            if (okrTaskMapper.updateSortByTid(task.getId(), sort) > 0) {
                return task.getId();
            }
        }
        return 0L;
    }

    /**
     * 根据当前目标获取上级目标列表
     * 
     * @param okrTask
     * @return
     * @throws Exception
     */
    public PageInfo<EgOkrTask> getParents(EgOkrTask okrTask) throws Exception {
        // 获取驿馆ID
        Long egid = okrTask.getPos() == null ? 0 : okrTask.getPos().getId();
        // 获取当前目标的标识以及截止时间
        Integer timing = okrTask.getTiming();
        Date etime = okrTask.getEtime();
        // 上级目标的标识
        Integer parentTiming = null;
        switch (timing) {
        case EgTimingType.QUARTER_TARGET:
            parentTiming = EgTimingType.YEAR_TARGET;
            break;
        case EgTimingType.MONTH_TARGET:
            parentTiming = EgTimingType.QUARTER_TARGET;
            break;
        case EgTimingType.WEEK_TARGET:
            parentTiming = EgTimingType.MONTH_TARGET;
            break;
        default:
            break;
        }
        // 获取季度年的开始月份
        Integer bmonth = tavernService.getBmonthByFid(egid);
        // 定义查询结果
        List<EgOkrTask> result = new ArrayList<>();
        // 获取目标列表
        List<OKRTaskEntity> entities = new ArrayList<>();
        if (parentTiming != null && etime != null) {
            List<Date> dates = okrTaskUtil.intervalDate(parentTiming, etime, bmonth);
            List<String> dateStr = DateUtil.dateToString(dates.get(0), dates.get(1));
            entities = okrTaskMapper.getParents(egid, parentTiming, dateStr.get(0), dateStr.get(1));
        }
        PageInfo<OKRTaskEntity> oldPageInfo = new PageInfo<>(entities);
        if (entities != null && entities.size() > 0) {
            result = entities.stream().map(r -> r.createRelateOkrTask()).collect(Collectors.toList());
        }
        return new PageInfo<>(result, oldPageInfo);
    }

    /**
     * 定时清除通用任务删除状态为1的工作任务及其关键项
     * 
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    @Scheduled(cron = "${timedDel.date}")
    public void timedDel() throws Exception {
        // 删除工作任务
        okrTaskMapper.del();
        // 删除关键项
        okrTaskMapper.delKrs();
    }

    /**
     * 任务状态转换时更新任务排序
     * 
     * @param okrtask
     * @param updateokr
     * @return
     * @throws Exception
     */
    private Long updateSortByStatus(EgOkrTask okrtask, EgOkrTask updateokr) throws Exception {

        // 获取到原状态的任务数量
        int updateStatus = updateokr.getStatus();
        int originalCount = countByStatus(okrtask.getPos(), okrtask.getStatus());
        int updateCount = countByStatus(okrtask.getPos(), updateStatus);
        EgOKRTaskEntity entity = okrTaskMapper.selectByPrimaryKey(okrtask.getId());
        // 原任务排序
        int tasksort = entity.getSort();
        int result = 0;
        // 如果状态是由进行中 -> 暂停 或者 由 暂停 -> 进行中，不改变工作任务顺序
        if (((okrtask.getStatus() & EgTaskStatus.STATUS_HANDLE) == EgTaskStatus.STATUS_HANDLE)
                && ((updateStatus & EgTaskStatus.STATUS_PAUSE) == EgTaskStatus.STATUS_PAUSE)
                || ((okrtask.getStatus() & EgTaskStatus.STATUS_PAUSE) == EgTaskStatus.STATUS_PAUSE)
                        && ((updateStatus & EgTaskStatus.STATUS_HANDLE) == EgTaskStatus.STATUS_HANDLE)) {
            return okrtask.getId();
        }
        // 如果当前任务的sort不为之前状态中的尾部，则需要对影响到的任务重新进行排序
        if (tasksort != originalCount) {
            String sortSql = buildSortSql(tasksort, originalCount, okrtask.getStatus(), okrtask.getPos().getId(),
                    okrtask.getPos().getType().getOtid(), false);
            result = okrTaskMapper.updateSort(sortSql, false);
        } else {
            result = 1;
        }
        // 在新的状态中，更新该任务的sort
        if (result > 0) {
            if (okrTaskMapper.updateSortByTid(okrtask.getId(), updateCount + 1) > 0)
                return okrtask.getId();
        }
        return null;
    }

    /**
     * 构建query查询条件
     * 
     * @param filter
     * @return
     * @throws Exception
     */
    private String buildQuerySQL(OkrTaskFilter filter) throws Exception {
        String whereSql = "";

        List<String> whereSqlList = new ArrayList<>();

        // 声明过滤条件
        Integer otype = EgOType.OKR_TASK;
        Long id = filter.getId() == null ? 0 : filter.getId();
        Boolean buid = filter.getBuid() == null ? false : filter.getBuid();
        // String name = filter.getName() == null ? "" : filter.getName();
        Integer status = filter.getStatus();
        Long douid = filter.getDouid() == null ? 0 : filter.getDouid();
        Integer timing = filter.getTiming();

        // 1、查询工作任务列表
        whereSqlList.add(" et.otype = " + otype);
        // 任务删除状态为0（未删除）
        whereSqlList.add("et.del_flag = 0");
        // 2、Id大于0并且为对象Id
        if (id > 0 && !buid) {
            // 3、根据驿馆Id和驿馆类型查询驿馆中的工作任务列表
            whereSqlList.add(" eg.egid = " + id);
            whereSqlList.add(" et.pos_otype = " + EgOType.TAVERN);
        }
        // 4、判断被指派人Id是否大于0，根据被指派人Id查询 指派给该用户 工作任务列表
        if (douid > 0) {
            whereSqlList.add(" eot.douid = " + douid);
        }
        // 5、如果状态不为空
        if (status != null) {
            // 如果状态为进行中，将进行中/延误处理和已暂停的任务全部查询出来
            if ((status & EgTaskStatus.STATUS_HANDLE) == EgTaskStatus.STATUS_HANDLE) {
                whereSqlList.add(" et.status in (" + status + ", " + (status | EgTaskStatus.STATUS_DELAY) + ", "
                        + EgTaskStatus.STATUS_PAUSE + ")");
            }
            // 否则，如果不为延误状态，根据状态查询【当前状态+当前状态（已延误）】的工作任务列表
            else if (status != EgTaskStatus.STATUS_DELAY) {
                whereSqlList.add(" et.status in (" + status + ", " + (status | EgTaskStatus.STATUS_DELAY) + ")");
            }
        }
        // 6、判断任务计时类型不为空，根据timing查询对应计时单位的工作任务列表
        if (timing != null) {
            whereSqlList.add(" timing = " + timing);
        }
        // 8、设置查询条件AND连接符
        if (whereSqlList.size() > 0) {
            whereSql += String.join(" AND ", whereSqlList);
        }

        return whereSql;
    }

    /**
     * 构建排序sql语句
     * 
     * @param filter
     * @param myworkbench
     * @return
     * @throws Exception
     */
    private String buildOrderSql(OkrTaskFilter filter, boolean myworkbench) throws Exception {
        Boolean priority = filter.getbPriority() == null ? false : filter.getbPriority();
        String orderSql = "";
        if (myworkbench) {
            orderSql += " ORDER BY";
            // 9、是否根据优先级排序priority
            if (priority) {
                orderSql += " priority DESC, ";
            }
            orderSql += " A.ctime DESC";
        } else {
            Integer status = filter.getStatus();
            orderSql = " ORDER BY sort";
            if (status == EgTaskStatus.STATUS_FINISH) {
                orderSql = " ORDER BY sort DESC";
            }
        }
        return orderSql;
    }

    /**
     * 构造查询工作台工作任务列表条件
     * 
     * @param filter
     * @param currentuid
     * @return
     * @throws Exception
     */
    private String buildMyworkbenchSQL(OkrTaskFilter filter, Long currentuid) throws Exception {
        String whereSql = "";

        List<String> whereSqlList = new ArrayList<>();

        // 声明过滤条件
        Long fid = filter.getFid() == null ? 0 : filter.getFid();
        Integer otype = EgOType.OKR_TASK;
        Long id = filter.getId() == null ? 0 : filter.getId();
        Boolean buid = filter.getBuid() == null ? false : filter.getBuid();
        Integer status = filter.getStatus();
        Long douid = filter.getDouid() == null ? 0 : filter.getDouid();
        Integer timing = filter.getTiming() == null ? 0 : filter.getTiming();

        List<Long> egidList = null;
        List<Long> taskIds = null;

        // 工作任务删除状态必须为0
        whereSqlList.add(" et.del_flag = 0 ");

        // 1、查询门派为fid下的所有工作任务列表，用于查看我的工作台的工作任务列表
        if (fid != null) {
            // 2、如果当前用户ID等于创建者ID（id）或者等于被指派人Id（douid）
            if ((currentuid == id && buid) || currentuid == douid) {
                // 如果fid > 0 , 查询用户在该门派中创建/被指派的工作任务列表；否则，查询该用户创建/被指派的所有工作任务
                if (fid > 0)
                    whereSqlList.add(" ef.fid = " + fid);
            } else {
                // 3、否则，查询当前登录用户和创建者/被指派人所处的相同驿馆ID列表
                if (id > 0 && buid) {
                    egidList = okrTaskMapper.getEgids(currentuid, id, fid);
                } else if (douid > 0) {
                    egidList = okrTaskMapper.getEgids(currentuid, douid, fid);

                }
                // 4、如果驿馆列表不为空，查询该驿馆中工作任务列表
                if (egidList != null && egidList.size() > 0) {
                    whereSqlList.add(" eg.egid in (" + StringUtils.join(egidList, ",") + ")");
                }
                // 5、否则，不存在工作任务，返回null
                else {
                    return null;
                }
            }
        }

        // 6、查询工作任务列表
        whereSqlList.add(" et.otype = " + otype);

        // 7、ID大于0并且为任务发布人，查询发布的工作任务列表
        if (id > 0 && buid) {
            whereSqlList.add(" et.cuid = " + id);
        }
        // 8、如果状态不为空，并且不为延误状态，根据状态查询【当前状态+当前状态（已延误）】的工作任务列表
        if (status != null && status != EgTaskStatus.STATUS_DELAY) {
            // 如果被指派人有被指派关键项，将被指派的任务和关键项对应的任务都查询出来， 否则，只需查询被指派的任务
            whereSqlList.add(" et.status in (" + status + ", " + (status | EgTaskStatus.STATUS_DELAY) + ")");
        }
        // 9、如果被指派人不为空并且 状态为null，根据被指派人Id查询【计划中+进行中+已暂停】的工作任务列表， 即任务状态不是已完成的任务列表
        if (douid > 0 && status == null) {
            whereSqlList.add(EgTaskStatus.STATUS_FINISH + " & et.status <> " + EgTaskStatus.STATUS_FINISH);
        }
        // 10、判断被指派人Id是否大于0，根据被指派人Id查询 指派给该用户 工作任务列表
        if (douid > 0) {
            // 只有有指派人，才能获取被指派的关键项对应的任务列表，
            taskIds = krService.taskIdsByKR(douid, status, egidList);
            whereSqlList.add(" eot.douid = " + douid);
        }
        // 11、判断任务计时类型不为空，根据timing查询对应计时单位的工作任务列表
        if (timing != 0) {
            whereSqlList.add(" timing = " + timing);
        }
        // 13、设置查询条件AND连接符
        if (whereSqlList.size() > 0) {
            whereSql += String.join(" AND ", whereSqlList);
        }

        // 如果被指派人有被指派关键项，将被指派的任务和关键项对应的任务都查询出来， 否则，只需查询被指派的任务
        if (taskIds != null && taskIds.size() > 0) {
            // whereSqlList.add(" (eot.douid = " + douid + " or et.tid in (" +
            // StringUtils.collectionToDelimitedString(taskIds, ",") + "))");
            whereSql = "( " + whereSql + ") or et.tid in (" + StringUtils.join(taskIds, ",")
                    + ")";
        }
        return whereSql;
    }

    /**
     * 根据更新参数传递的状态和数据库中工作任务原状态确定要更新的状态
     * 
     * @param okrstatus
     *            原工作任务状态
     * @param updatestatus
     *            更新的工作任务状态
     * @return
     * @throws Exception
     */
    private Integer getStatus(Integer okrstatus, Integer updatestatus) throws Exception {
        Integer status = null;
        switch (updatestatus) {
        // 1、开始任务
        case EgTaskStatus.STATUS_HANDLE:
            // 2、如果原工作任务状态为未开始/未开始已延误，更新任务状态为进行中/延误处理
            if (okrstatus == EgTaskStatus.STATUS_NEW
                    || okrstatus == (EgTaskStatus.STATUS_NEW | EgTaskStatus.STATUS_DELAY)) {
                status = okrstatus + EgTaskStatus.STATUS_HANDLE;
            }
            // 3、如果员工作状态为已完成/延误完成，更新任务状态为进行中/延误处理
            else if ((okrstatus & EgTaskStatus.STATUS_FINISH) == EgTaskStatus.STATUS_FINISH) {
                status = okrstatus - EgTaskStatus.STATUS_HANDLE;
            }
            // 4、如果原工作状态为暂停中，更新任务状态为进行中，更新任务截止时间为null，同时，前端提示用户重新设置任务截止时间
            else if ((okrstatus & EgTaskStatus.STATUS_PAUSE) == EgTaskStatus.STATUS_PAUSE) {
                status = EgTaskStatus.STATUS_HANDLE;
            }
            break;
        // 5、完成任务
        case EgTaskStatus.STATUS_FINISH:
            // 6、只有当任务状态为进行中/延误处理时，才能完成任务，并更新任务状态为已完成/延误完成
            if ((okrstatus & EgTaskStatus.STATUS_HANDLE) == EgTaskStatus.STATUS_HANDLE) {
                status = okrstatus + EgTaskStatus.STATUS_FINISH - EgTaskStatus.STATUS_HANDLE;
            }
            break;
        // 8、暂停任务
        case EgTaskStatus.STATUS_PAUSE:
            // 9、只有当任务状态为进行中/延误处理时，才能暂停任务，并更新任务状态为已暂停
            if ((okrstatus & EgTaskStatus.STATUS_HANDLE) == EgTaskStatus.STATUS_HANDLE) {
                status = EgTaskStatus.STATUS_PAUSE;
            }
        default:
            break;
        }
        return status;
    }

    /**
     * 根据更新参数传递的任务截止时间和数据库中工作任务的截止时间和状态确定工作任务状态
     * 
     * @param okrtask
     *            原工作任务
     * @param updateokr
     *            更新的工作任务参数
     * @return
     * @throws Exception
     */
    private EgOkrTask updateStatusByEtime(EgOkrTask okrtask, EgOkrTask updateokr) throws Exception {
        // 1、获取更新任务中的被指派人
        EgUser douser = updateokr.getDouser();
        // 2、获取数据库中工作任务截止时间和任务状态
        Integer oldstatus = okrtask.getStatus();
        // 3、获取更新工作任务的截止时间
        Date updateDate = updateokr.getEtime();
        // 4、如果有被指派人，并且原状态为进行中，修改截止日期并且当前日期大于截止日期，状态为已延误，否则状态为未开始
        if ((oldstatus & EgTaskStatus.STATUS_HANDLE) == EgTaskStatus.STATUS_HANDLE && douser != null
                && !douser.equals(okrtask.getDouser())) {
            if (updateDate != null && DateUtil.dateCompare(updateDate, new Date()) < 0) {
                updateokr.setStatus(EgTaskStatus.STATUS_DELAY);
            } else {
                updateokr.setStatus(EgTaskStatus.STATUS_NEW);
            }
            // 状态更新时，更新任务排序
            if (updateSortByStatus(okrtask, updateokr) == null) {
                throw new Exception("任务更新失败！");
            }
            return updateokr;
        }
        // 5、如果时间相等，不改变截止日期和状态
        if (updateDate == null)
            return updateokr;
        // 6、否则修改实际截止时间为截止日期当天下午6点
        updateokr.setEtime(DateUtil.dateTime(updateDate, 18, 0, 0));
        // 7、否则，将任务状态已延误/延误处理/延误完成 改为 计划中/进行中/已完成
        if (DateUtil.dateCompare(new Date(), DateUtil.addDay(updateDate, 1)) < 0) {
            if ((oldstatus & EgTaskStatus.STATUS_DELAY) == EgTaskStatus.STATUS_DELAY) {
                updateokr.setStatus(oldstatus ^ EgTaskStatus.STATUS_DELAY);
            }
        }
        // 8、如果更新时间小于原截止时间，将任务状态计划中/进行中/已完成 改为 已延误/延误处理/延误完成
        else {
            if (oldstatus != EgTaskStatus.STATUS_PAUSE
                    && (oldstatus & EgTaskStatus.STATUS_DELAY) == EgTaskStatus.STATUS_NEW) {
                updateokr.setStatus(oldstatus | EgTaskStatus.STATUS_DELAY);
            }
        }
        return updateokr;
    }

    /**
     * 工作任务动作包括以下情形，其拼接语句格式类似： 创建/开始/删除/完成/评论(见评论接口)/重做/暂停/上传文件、删除文件
     * 
     * @param okrTask
     * @param atid
     * @param uid
     * @param files
     * @return
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    private Boolean saveAction(EgOkrTask okrTask, Integer atid, Long uid, List<EgFile> files) throws Exception {
        // 操作者信息
        EgUser user = userService.getUser(uid, false);
        if (user == null) {
            return false;
        }
        // 被操作对象的类型ID/被操作对象的类型名称/被操作对象的名称
        Integer otype = EgOType.OKR_TASK;
        String otypeName = configInfo.otypes().get(otype).getName();
        String oname = okrTask.getName();
        // 被操作对象
        EgObject obj = new EgObject(okrTask.getId(), oname, new EgOType(otype, null));
        // 动作名称
        String actionName = configInfo.actionTypes().get(atid).getName();
        EgOtAction otAction = configInfo.actionTypes(otype).get(atid);
        // 结果对象类型
        EgOType rtype = otAction.getRtype();
        // 动作标识
        Integer actFlag = otAction.getFlag();
        EgObject result = new EgObject(user.getId(), user.getName(), rtype);
        // 动作发生的位置
        EgObject pos = null;
        if (okrTask != null) {
            pos = new EgObject(okrTask.getPos().getId(), null, new EgOType(okrTask.getPos().getType().getOtid(), null));
        }
        // 动作拼接语句
        String rcontent = user.getName() + " " + actionName + "了 " + otypeName + " " + oname;
        switch (atid) {
        // 如果是创建工作任务，被操作对象类型为驿馆，结果对象为工作任务
        case EgActionType.CREATE:
            otype = EgOType.TAVERN;
            otAction = configInfo.actionTypes(otype).get(atid);
            rtype = otAction.getRtype();
            actFlag = otAction.getFlag();
            // 获取驿馆信息
            EgTavern taven = tavernService.getById(okrTask.getPos().getId());
            if (taven == null) {
                return false;
            }
            obj = new EgObject(taven.getId(), taven.getName(), new EgOType(otype, null));
            result = new EgObject(okrTask.getId(), oname, rtype);
            break;
        case EgActionType.DELETE:
            // 如果是删除文件,被操作对象类型为文件，结果对象为工作任务;只作为操作记录。
            if (files != null && files.size() > 0) {
                otype = EgOType.FILE;
                otAction = configInfo.actionTypes(otype).get(atid);
                rtype = otAction.getRtype();
                actFlag = otAction.getFlag();
                oname = files.get(0).getName();
                obj = new EgObject(files.get(0).getId(), oname, new EgOType(otype, null));
                result = new EgObject(okrTask.getId(), okrTask.getName(), rtype);
                otypeName = configInfo.otypes().get(EgOType.FILE).getName();
                rcontent = user.getName() + " " + actionName + "了 " + otypeName + " " + oname;
            } else {
                // 如果是删除工作任务，被操作对象类型为工作任务，结果对象为驿馆;只作为动态。
                taven = tavernService.getById(okrTask.getPos().getId());
                if (taven == null) {
                    return false;
                }
                result = new EgObject(taven.getId(), taven.getName(), rtype);
            }
            break;
        // 如果是上传文件，被操作对象类型为工作任务，结果对象为用户;只作为操作记录。
        case EgActionType.UPLOAD:
            if (files != null && files.size() > 0) {
                List<String> onames = files.stream().map(f -> f.getName()).collect(Collectors.toList());
                oname = String.join(", ", onames);
                otypeName = configInfo.otypes().get(EgOType.FILE).getName();
                rcontent = user.getName() + " " + actionName + "了 " + otypeName + " " + oname;
                actFlag = configInfo.actionTypes(otype).get(atid).getFlag();
            }
            break;
        default:
            break;
        }
        if (!actionService.create(atid, obj, result, rcontent, pos, uid, actFlag)) {
            return false;
        }
        return true;
    }

    /**
     * 更新工作任务的动作:包括更新 截止日期/优先级/目标标识/任务标题/任务描述;指派或取消指派动
     * 
     * @param oldtask
     * @param okrTask
     * @param uid
     * @return
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    private Boolean updateAction(EgOkrTask oldtask, EgOkrTask okrTask, Long uid) throws Exception {
        // 操作者信息
        EgUser user = userService.getUser(uid, false);
        if (user == null) {
            return false;
        }
        // 默认动作为更新/动作名称
        int atid = EgActionType.UPDATE;
        String actionName = configInfo.actionTypes().get(atid).getName();
        // 被操作对象的类型ID/被操作对象的名称
        Integer otype = EgOType.OKR_TASK;
        String oname = oldtask.getName();
        // 被操作对象(默认为工作任务)
        EgObject obj = new EgObject(oldtask.getId(), oname, new EgOType(otype, null));
        EgOtAction otAction = configInfo.actionTypes(otype).get(atid);
        // 结果对象类型/结果对象(默认为当前用户)
        EgOType rtype = otAction.getRtype();
        // 动作标识
        Integer actFlag = otAction.getFlag();
        EgObject result = new EgObject(uid, user.getName(), rtype);
        // 动作发生的位置
        EgObject pos = new EgObject(oldtask.getPos().getId(), null,
                new EgOType(oldtask.getPos().getType().getOtid(), null));
        // 动作拼接语句
        String rcontent = "";
        Boolean flag = false;

        Date etime = okrTask.getEtime();
        Integer priority = okrTask.getPriority();
        Integer timing = okrTask.getTiming();
        Long oldDouid = oldtask.getDouser().getId();
        Long douid = okrTask.getDouser().getId();
        String name = okrTask.getName();
        String oldName = oldtask.getName();
        String content = okrTask.getContent();
        String oldContent = oldtask.getContent();
        // 更新任务的截止日期
        if (etime != null && oldtask.getEtime() != null && DateUtil.dateCompare(etime, oldtask.getEtime()) != 0) {
            flag = true;
            rcontent = user.getName() + " " + actionName + "了 截止日期 为 " + DateUtil.formatDate(etime, "");
        } else if (etime == null && oldtask.getEtime() != null) {
            flag = true;
            rcontent = user.getName() + " 设置该任务无截止日期";
        } else if (etime != null && oldtask.getEtime() == null) {
            flag = true;
            rcontent = user.getName() + " " + actionName + "了 截止日期 为 " + DateUtil.formatDate(etime, "");
        }
        // 更新任务的优先级
        if (priority != null && !oldtask.getPriority().equals(priority)) {
            flag = true;
            String rcontent1 = user.getName() + " " + actionName + "了 优先级 为 ";
            switch (priority) {
            case EgProirity.PRIORITY_LOW:
                rcontent = rcontent1 + "普通";
                break;
            case EgProirity.PRIORITY_MIDDLE:
                rcontent = rcontent1 + "紧急";
                break;
            case EgProirity.PRIORITY_HIGH:
                rcontent = rcontent1 + "非常紧急";
                break;
            default:
                break;
            }
        }
        // 更新任务的目标标识
        if (timing != null && !timing.equals(oldtask.getTiming())) {
            flag = true;
            String rcontent1 = user.getName() + " " + actionName + "了 目标标识 为 ";
            switch (timing) {
            case EgTimingType.WEEK_TARGET:
                rcontent = rcontent1 + "周目标";
                break;
            case EgTimingType.MONTH_TARGET:
                rcontent = rcontent1 + "月目标";
                break;
            case EgTimingType.QUARTER_TARGET:
                rcontent = rcontent1 + "季度目标";
                break;
            case EgTimingType.YEAR_TARGET:
                rcontent = rcontent1 + "年目标";
                break;
            default:
                break;
            }
        }
        // 指派任务
        if (douid != null && douid > 0 && !douid.equals(oldDouid)) {
            flag = true;
            atid = EgActionType.DISPATCH;
            actionName = configInfo.actionTypes().get(atid).getName();
            EgUser doUser = userService.getUser(douid, false);
            if (doUser == null) {
                return false;
            }
            rcontent = user.getName() + " 将 " + oname + " " + actionName + "给了 " + doUser.getName();
        }
        // 取消指派
        if (oldDouid != null && oldDouid > 0 && douid == 0) {
            flag = true;
            atid = EgActionType.DISPATCH;
            EgUser oldDoUser = userService.getUser(oldDouid, false);
            if (oldDoUser == null) {
                return false;
            }
            rcontent = user.getName() + " 取消了 " + oldDoUser.getName() + "的" + oname;
        }
        // 更新任务标题
        if (name != null && !name.trim().equals("") && !name.equals(oldName)) {
            flag = true;
            obj.setName(name);
            rcontent = user.getName() + " " + actionName + "了 任务标题 为 " + name;
        }
        // 更新任务描述
        if (StringUtils.isNotBlank(content) && !content.equals(oldContent)) {
            flag = true;
            rcontent = user.getName() + " " + actionName + "了 任务描述";
        }
        if (flag) {
            if (!actionService.create(atid, obj, result, rcontent, pos, uid, actFlag)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 根据状态查询工作任务对应个数
     * 
     * @param pos
     * @param status
     * @return
     * @throws Exception
     */
    private Integer countByStatus(EgObject pos, Integer status) throws Exception {
        String countsql = " pos_oid = " + pos.getId() + " and pos_otype = " + pos.getType().getOtid() + " and otype = "
                + EgOType.OKR_TASK + " and del_flag = 0";
        if (status == null) {
            return okrTaskMapper.countByStatus(countsql);
        } else if ((status & EgTaskStatus.STATUS_DELAY) == EgTaskStatus.STATUS_DELAY) {
            status = status ^ EgTaskStatus.STATUS_DELAY;
        }
        if ((status & EgTaskStatus.STATUS_HANDLE) == EgTaskStatus.STATUS_HANDLE) {
            countsql += " and status in (" + status + ", " + (status | EgTaskStatus.STATUS_DELAY) + ", "
                    + EgTaskStatus.STATUS_PAUSE + ")";
        } else {
            countsql += " and status in (" + status + ", " + (status | EgTaskStatus.STATUS_DELAY) + ")";
        }
        return okrTaskMapper.countByStatus(countsql);
    }

    /**
     * 排序时获取当前被排序任务所在任务列表的sql语句
     * 
     * @param firstsort
     * @param lastsort
     * @param status
     * @param posOid
     * @param posOtype
     * @param bUp
     * @return
     * @throws Exception
     */
    private String buildSortSql(int firstsort, int lastsort, int status, Long posOid, Integer posOtype, Boolean bUp)
            throws Exception {
        // updateSort
        String whereSql = "";

        List<String> whereSqlList = new ArrayList<>();
        // 如果向上拖拽
        if (bUp) {
            whereSqlList.add("sort >= " + firstsort);
            whereSqlList.add(" " + lastsort + " > sort");
        } else {
            whereSqlList.add("sort > " + firstsort);
            whereSqlList.add(" " + lastsort + " >= sort");
        }
        // 如果状态为进行中/延误进行中/暂停，查询该三个状态下的任务
        if ((status & EgTaskStatus.STATUS_HANDLE) == EgTaskStatus.STATUS_HANDLE
                || status == EgTaskStatus.STATUS_PAUSE) {
            whereSqlList.add(" status in (" + EgTaskStatus.STATUS_HANDLE + ", "
                    + (EgTaskStatus.STATUS_HANDLE | EgTaskStatus.STATUS_DELAY) + ", " + EgTaskStatus.STATUS_PAUSE
                    + ")");
        } else {
            if ((status & EgTaskStatus.STATUS_FINISH) == EgTaskStatus.STATUS_FINISH) {
                whereSqlList.add(" status in (" + EgTaskStatus.STATUS_FINISH + ", "
                        + (EgTaskStatus.STATUS_FINISH | EgTaskStatus.STATUS_DELAY) + ")");
            } else {
                whereSqlList.add(" status in (" + EgTaskStatus.STATUS_NEW + ", " + EgTaskStatus.STATUS_DELAY + ")");
            }
        }
        whereSqlList.add("et.pos_oid = " + posOid);
        whereSqlList.add("et.pos_otype = " + posOtype);
        whereSqlList.add("et.del_flag = 0");

        // 设置查询条件AND连接符
        if (whereSqlList.size() > 0) {
            whereSql += String.join(" AND ", whereSqlList);
        }
        return whereSql;
    }

    /**
     * 移除当前任务关联的上级和下级目标
     * 
     * @param tid
     * @return
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    private Boolean removeTargets(Long tid) throws Exception {
        // 构造条件
        Example example = new Example(EgOKRTaskEntity.class);
        example.and().andEqualTo("tid", tid).orEqualTo("parent", tid);
        List<EgOKRTaskEntity> entities = okrTaskMapper.selectByExample(example);
        // 存储待更新的工作任务列表
        List<EgOKRTaskEntity> upEntities = new ArrayList<>();
        if (entities != null && entities.size() > 0) {
            for (EgOKRTaskEntity entity : entities) {
                entity.setParent(null);
                upEntities.add(entity);
            }
        }
        // 将关联的目标设置为null
        if (upEntities != null && upEntities.size() > 0) {
            if (okrTaskMapper.updateOkrTaskList(upEntities) == 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * 更新目标的标识和截止时间
     * 
     * @param okrTask
     * @param updateOkr
     * @return
     * @throws Exception
     */
    @Transactional(transactionManager = "eguanTransactionManager", rollbackFor = Exception.class)
    private EgOkrTask updateTimingAndEtime(EgOkrTask okrTask, EgOkrTask updateOkr) throws Exception {
        Integer oldTiming = okrTask.getTiming();
        Date oldEtime = okrTask.getEtime();
        Integer upTiming = updateOkr.getTiming();
        Date upEtime = updateOkr.getEtime();
        // 原为目标，修改了Timing(数据库中对应的颜色也同步修订为相应的默认颜色,首先将原来颜色置为空)
        if (oldTiming != null && (upTiming != null && !upTiming.equals(oldTiming))) {
            // 去除目标关联
            if (!removeTargets(okrTask.getId())) {
                throw new RuntimeException("更新失败！");
            }
            updateOkr.setParent(null);
            updateOkr.setColor(null);
            // 更换目标标识，需要重新计算该标识对应的默认颜色，存入到数据库（前提是color必须为null）
            updateOkr.setTiming(upTiming);
        }
        // 将目标设为普通任务(原目标标识不为空)
        if (oldTiming != null && upTiming == null) {
            // 去除目标关联，没有目标标识，color设为null
            if (!removeTargets(okrTask.getId())) {
                throw new RuntimeException("更新失败！");
            }
            updateOkr.setParent(null);
            updateOkr.setColor(null);
        }
        // 将截止时间设为null(原截止时间不为null,并且目标标识不为空)
        if ((oldEtime != null && oldTiming != null) && upEtime == null) {
            // 去除目标关联，color设为null
            if (!removeTargets(okrTask.getId())) {
                throw new RuntimeException("更新失败！");
            }
            updateOkr.setParent(null);
            updateOkr.setColor(null);
        }
        return updateOkr;
    }
}
